#pragma once
#include <iostream>
#include <vector>
#include "Mutex.hpp"
#include "Sem.hpp"
using namespace MutexModule;
using namespace SemModule;
<<<<<<< HEAD
extern int gcap; // 环形队列大小的外部声明
=======
extern int gcap; // 环形队列大小的声明
>>>>>>> 5b09c08c250e9d9f594a71640feff181ec4a6f13
// 生产的数据交给模板推导
template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _cap(cap),
          _rq(cap),
          _empty(cap),
          _pro_index(0),
          _full(0),
          _con_index(0) {}
    void Enqueue(const T &in)
    {
        // 生产者
        // 1.申请信号量，空位置信号量
        _empty.P();
        {                                    // {}内就是一个临界区，也是一个局部域
            LockGuard lockGuard(_pro_mutex); // 利用C++语法特性加锁
            // 2.生产
            _rq[_pro_index] = in;
            // 3.更新下标
            _pro_index++;
            // 4.维持环形特性
            _pro_index %= _cap;
        }
        _full.V(); // 放在临界区之后，提高并发度
    }
    void Pop(T *out)
    {
        // 消费者
        // 1.申请信号量，数据信号量
        _full.P();
        {                                    // 临界区
            LockGuard lockGuard(_con_mutex); // 利用C++语法特性加锁
            // 2.消费
            *out = _rq[_con_index];
            // 3.更新下标
            _con_index++;
            // 4.维持环形特性
            _con_index %= _cap;
        }
        _empty.V(); // 放在临界区之后，提高并发度
    }
    ~RingQueue() = default;

private:
    std::vector<T> _rq;
    int _cap;
    // 生产者
    Sem _empty;     // 空位置
    int _pro_index; // 准备生成的下标
    // 消费者
    Sem _full;      // 数据
    int _con_index; // 准备消费的下标
    // 维护多生产者，多消费者的锁，考虑效率问题，这里2把锁
    Mutex _pro_mutex; // 生产者锁
    Mutex _con_mutex; // 消费者锁
};
